<template>
  <div class="table-container">
    <div class="tree-side" v-if="treeSide.show">
      <h1>{{ treeSide.title }}</h1>
      <el-tree ref="tableTreeSide" :data="treeData" :props="treeProps" node-key="id" :expand-on-click-node="false" accordion :default-expanded-keys="defaultExpandNodes" :show-checkbox="false">
        <template #default="{ node }">
          <div class="add-tree-node" v-if="node.data.type == 'input'">
            <el-input ref="treeInputRef" v-model="node.data.label" @blur="addNewNode(node)" @keyup.enter.native="treeInputRef.blur()"></el-input>
          </div>
          <div class="custom-tree-node" v-else @mouseenter="node.data.showIcon = true" @mouseleave="node.data.showIcon = false">
            <span class="node-label" @click="handleClickNode(node)">{{ node.label }}</span>
            <span class="node-icon" v-show="node.data.showIcon">
              <el-icon v-if="treeSide.allowAdd" @click="handleAddNode(node)"><Plus /></el-icon>
              <el-icon style="margin-left: 10px" v-if="node.data.id != 0 && treeSide.allowDel" @click="deleteNode(node)"><Delete /></el-icon>
            </span>
          </div>
        </template>
      </el-tree>
    </div>
    <div class="table-main" v-loading="load" :style="{ width: treeSide.show ? '85%' : '100%' }">
      <Transition name="autoHeight">
        <div class="table-search" v-if="config.search.config.length != 0" v-show="searchFormDown">
          <HETForm1 ref="searchFormEl" v-model="searchForm" :inline="true" :formConfig="config.search.config"> </HETForm1>
          <div class="flex">
            <!-- <span style="font-size: 14px; margin-right: 10px"
              >模糊查询：<el-switch
                v-model="operator"
                active-value="like"
                inactive-value="="
                size="small"
              ></el-switch
            ></span> -->
            <el-button type="primary" icon="Search" @click="getTableData()">查询</el-button>
            <el-button icon="RefreshRight" @click="clearSearch">清空</el-button>
          </div>
        </div>
      </Transition>
      <div class="control-btn">
        <div class="btn-group">
          <template v-for="(item, index) in config.controlBtns" :key="index">
            <el-button v-if="item.type == 'delete'" :icon="markRaw(item.icon)" type="danger" :disabled="item.disabled ? item.disabled(selectData) : selectData.length == 0 ? true : false" @click="delSelectRows()">
              {{ item.name }}
            </el-button>
            <template v-else-if="item.render">
              <component :is="item.render(selectData)" />
            </template>
            <template v-else-if="item.type == 'slot'">
              <slot name="ctrlBtn"></slot>
            </template>
            <el-button v-else :icon="markRaw(item.icon)" :type="item.type" :disabled="item.disabled ? item.disabled(selectData) : false" @click="item.handleClick()">
              {{ item.name }}
            </el-button>
          </template>
        </div>
        <!-- <div class="table-search" v-if="config.search">
          <el-input
            v-model="searchKeys"
            style="width: 200px; height: 32px; margin-right: 12px"
            v-bind="config.search"
            :prefix-icon="Search"
          />
          <el-button type="primary" :icon="Search" @click="getTableData()"
            >查询</el-button
          >
          <el-button :icon="RefreshRight" @click="searchKeys = '';getTableData()"
            >清空</el-button
          >
        </div> -->
        <div class="control-other">
          <el-button v-if="config.search.config.length != 0" circle icon="Search" size="small" title="展开/收起筛选" @click="searchFormDown = !searchFormDown" />
          <!-- <el-popover
            :width="80"
            placement="bottom-end"
            trigger="click"
            @hide="popoverHideClick"
            @show="popoverShowClick"
          >
            <template #default>
              <el-checkbox-group v-model="state.columnsCheck">
                <el-checkbox
                  v-for="item in data.columns"
                  :key="item.prop || item.type"
                  :value="item.prop || item.type"
                  >{{ item.label }}
                </el-checkbox>
              </el-checkbox-group>
            </template>
            <template #reference>
              <el-button
                circle
                icon="SetUp"
                title="设置列显示隐藏"
                size="small"
              />
            </template>
          </el-popover> -->
        </div>
      </div>

      <el-table :data="tableData" ref="refTable" max-height="730" @select="select" :show-header="true" @select-all="select" row-key="id" show-overflow-tooltip>
        <template v-for="(item, index) in config.columns">
          <el-table-column v-if="item.type != 'slot'" :key="index" :type="item.type" :label="item.label" :prop="item.prop" :width="item.type == 'selection' ? 34 : item.width" :selectable="item.selectable" show-overflow-tooltip>
            <template v-if="item.custom?.type == 'text'" #default="scope">
              {{ item.custom.handleFunc(scope.row) }}
            </template>
            <template v-else-if="item.custom?.type == 'switch'" #default="scope">
              <el-switch v-model="scope.row[item.prop]" v-bind="item.custom.bind" :disabled="item.custom.disabledFn ? item.custom.disabledFn(scope.row) : false" inline-prompt @change="item.custom.handleFunc(scope.row)" />
            </template>
            <template v-else-if="item.custom?.type == 'button'" #default="scope">
              <template v-for="(btn, index) in item.custom.operatBtns">
                <template v-if="btn.type == 'delete'">
                  <el-popconfirm :title="btn.tip || '确定删除该记录?'" cancel-button-text="取消" confirm-button-text="确认" @confirm="btn.delConfirm ? btn.delConfirm(scope.row) : delCurrentRow([scope.row.id])">
                    <template #reference>
                      <el-button :key="index" size="small" type="text" :text="true" :disabled="btn.disabledFn ? btn.disabledFn(scope.row) : false">{{ btn.name }} </el-button>
                    </template>
                  </el-popconfirm>
                </template>
                <template v-else>
                  <el-button :key="index" v-bind="btn.setting ? btn.setting(scope.row) : {}" type="text" size="small" :text="true" :disabled="btn.disabledFn ? btn.disabledFn(scope.row) : false" @click="btn.handleClick(scope.row)">{{ btn.name }}</el-button>
                </template>
              </template>
            </template>
            <template v-else-if="item.render" #default="scope">
              <component :is="item.render(scope.row)" />
            </template>
            <template v-else-if="item.formatter" #default="scope">
              {{ item.formatter(scope.row) }}
            </template>
            <template v-else-if="item.type == 'expand'" #default="scope">
              {{ item.formatter(scope.row) }}
            </template>
          </el-table-column>
          <slot v-else :name="item.slotName ? item.slotName : ''"> </slot>
        </template>

        <!-- <template slot="empty"></template> -->
      </el-table>
      <div class="paginationWrap">
        <el-pagination
          style="justify-content: flex-end"
          :hide-on-single-page="false"
          :page-size="pageSize"
          :page-sizes="[10, 20, 50]"
          :page-count="maxPage ? maxPage : 1"
          :pager-count="7"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
          background
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        ></el-pagination>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, computed, onMounted, markRaw, nextTick, toRef } from 'vue'
import HETForm1 from './HETForm1.vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { commonApi } from '~/utils/axios/common.js'
import moment from 'moment'

const props = defineProps({
  // 表格配置
  config: {
    type: Object,
    default: {
      // 模块名
      module: null,
      // 搜索
      search: {
        form: {},
        config: []
      },
      sorts: ['id'],
      // 默认排序方式
      sorted: 'asc',
      // 列
      columns: [],
      // 表格顶部操作按钮
      controlBtns: []
    }
  },
  treeSide: {
    type: Object,
    default: {
      show: false,
      title: '',
      module: null,
      // props: null,
      filter: {
        field: '',
        operator: '=',
        value: null
      },
      allowAdd: false,
      allowDel: false
    }
  },
  // 请求额外参数
  query: {
    type: Object,
    default: null
  }
})
const maxPage = computed(() => {
  return total.value > 10000 ? Math.ceil(10000 / pageSize.value) : Math.ceil(total.value / pageSize.value)
})

// 显示or隐藏表单查询
const searchFormDown = ref(true)
// 查询条件
const searchForm = toRef(props.config.search?.form)
const treeFilter = toRef(props.treeSide.filter)
// 查询时的匹配模式（模糊查询like，精准查询=）
const operator = ref('=')
// 构造查询条件参数filters
const filters = computed(() => {
  let list = []
  if (treeFilter.value.value != null) {
    list.push(treeFilter.value)
  }
  if (props.query && Object.keys(props.query).length != 0) {
    Object.keys(props.query).forEach(key => {
      list.push({
        field: key,
        operator: '=',
        value: props.query[key]
      })
    })
  }
  for (var k in searchForm.value) {
    if (searchForm.value[k]) {
      list.push({
        field: k,
        operator: operator.value,
        value: searchForm.value[k]
      })
    }
  }

  return list
})
// 查询的字段
const columns = computed(() => {
  let cols = []
  // props.config.columns.forEach((item) => {
  //   if (item.prop) {
  //     cols.push({
  //       field: item.prop,
  //     });
  //   }
  // });
  return cols
})
// 表格相关
const tableData = ref([])
const total = ref(0)
const currentPage = ref(1)
const pageSize = ref(10)
const load = ref(false)
const selectData = ref([])

// 树形组件相关
const tableTreeSide = ref()
const treeData = ref([{ id: 0, name: '全部分组', child: [] }])
const treeProps = {
  children: 'child',
  label: 'name',
  value: 'id'
}
const defaultExpandNodes = [0]

onMounted(() => {
  getTreeSideData()
  getTableData()
})

// 多选
const select = selection => {
  selectData.value = selection
}
const handleSizeChange = val => {
  pageSize.value = val
  getTableData()
}
// 翻页
const handleCurrentChange = page => {
  currentPage.value = page
  getTableData()
}
// 清空查询条件
const clearSearch = () => {
  // searchForm.value = {}
  for (var k in searchForm.value) {
    searchForm.value[k] = null
  }
  getTableData()
}
const getTableData = query => {
  load.value = true
  if (props.config.selectApi) {
    let start, end
    if (props.config.search.form.timeRange) {
      start = moment(props.config.search.form.timeRange[0]).format('YYYY-MM-DD HH:mm:ss')
      end = moment(props.config.search.form.timeRange[1]).format('YYYY-MM-DD HH:mm:ss')
    }
    const params = {
      page: currentPage.value,
      size: pageSize.value,
      start,
      end,
      ...props.config.search.form,
      ...query
    }
    delete params.timeRange
    return props.config
      .selectApi(params)
      .then(res => {
        load.value = false
        tableData.value = res.data.data.rows
        total.value = res.data.data.total
        selectData.value = []
      })
      .catch(() => {
        load.value = false
      })
  }
  if (props.config.module) {
    const params = {
      page: currentPage.value,
      size: pageSize.value,
      filters: filters.value,
      sorts: props.config.sorts, //["id"],
      columns: columns.value,
      sorted: props.config.sorted
    }
    commonApi
      .generalQuery(props.config.module, params)
      .then(res => {
        load.value = false
        tableData.value = res.data.data
        total.value = res.data.total
        selectData.value = []
      })
      .catch(err => {
        load.value = false
      })
  }
}
// 表格批量删除
const delSelectRows = () => {
  if (selectData.value.length == 0) {
    ElMessage.error('请选择需要删除的选项!')
    return
  }
  ElMessageBox.confirm('确定要删除所选项？', '批量删除', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    center: true,
    closeOnClickModal: false,
    type: 'warning'
  }).then(() => {
    let params = selectData.value.map(item => {
      return item.id
    })
    delCurrentRow(params)
  })
}
const emit = defineEmits(['finishDel'])
// 单个删除
const delCurrentRow = params => {
  if (props.config.deleteApi) {
    return props.config.deleteApi(params).then(res => {
      res.data.succeed ? ElMessage.success('删除成功') : ElMessage.error(res.data.message)
      getTableData()
      emit('finishDel')
    })
  }
  if (props.config.module) {
    commonApi.generalDelete(props.config.module, params).then(res => {
      res.data.succeed ? ElMessage.success('删除成功') : ElMessage.error('删除失败')
      getTableData()
    })
  }
}

const getTreeSideData = () => {
  if (!props.treeSide.show) return
  const params = {
    filters: [],
    sorts: ['id'],
    columns: [],
    sorted: 'asc'
  }
  commonApi.generalQuery(props.treeSide.module, params).then(res => {
    res.data.data.forEach(item => {
      if (!item.child) {
        item['child'] = []
      }
    })
    treeData.value[0].child = res.data.data
  })
}

const treeInputRef = ref()
const handleAddNode = node => {
  node.expand()
  setTimeout(() => {
    node.data.child.unshift({
      pid: node.data.id,
      label: '',
      child: [],
      type: 'input'
    })
    nextTick(() => {
      treeInputRef.value.focus()
    })
  }, 300)
}
const addNewNode = node => {
  let params = {
    name: node.data.label,
    pid: node.data.pid
  }
  if (params.name != '') {
    commonApi
      .generalAdd(props.treeSide.module, params)
      .then(res => {
        res.data.succeed ? ElMessage.success('添加成功') : ElMessage.error('添加失败')
        getTreeSideData()
      })
      .catch(err => {
        tableTreeSide.value.remove(node)
      })
  } else {
    tableTreeSide.value.remove(node)
  }
}
const deleteNode = node => {
  ElMessageBox.confirm('确定要删除分组' + node.data.name + '？', '删除分组', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    center: true,
    closeOnClickModal: false,
    type: 'warning'
  }).then(() => {
    commonApi.generalDelete(props.treeSide.module, [{ id: node.data.id }]).then(res => {
      res.data.succeed ? ElMessage.success('删除成功') : ElMessage.error('删除失败')
      getTreeSideData()
    })
  })
}
const handleClickNode = node => {
  treeFilter.value.value = node.data.id
  getTableData()
}

defineExpose({ getTableData, selectData })
</script>

<style lang="scss" scoped>
.table-container {
  display: flex;
  justify-content: space-between;
  .tree-side {
    width: 14%;
    h1 {
      font-size: 16px;
      font-weight: 700;
      border-bottom: 1px solid #eee;
      padding: 15px 10px;
      margin-bottom: 10px;
    }
    .custom-tree-node {
      width: 100%;
      display: flex;
      justify-content: space-between;
      cursor: default;
      .node-label:hover {
        text-decoration: underline;
        cursor: pointer;
      }
      .node-icon {
        display: flex;
        align-items: center;
        cursor: pointer;
        :deep(.el-icon):hover {
          color: #8901b4;
        }
      }
    }
    .add-tree-node {
      :deep(.el-input) {
        height: 22px;
      }
    }
  }
  .table-main {
    width: 85%;
  }
}
.table-search {
  display: flex;
  // justify-content: space-between;
  border-bottom: 1px solid #ddd;
  // padding: 10px 0 15px 0;
  // transition: all 0.2s ease-out;
}
.control-btn {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 10px 0;
}
.operation {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}
.paginationWrap {
  padding-top: 15px;
  :deep(.el-pagination__sizes .el-select) {
    width: 95px;
  }
  :deep(.el-pagination > *.is-last) {
    margin-left: 5px;
  }
  :deep(.el-pager .number) {
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0.15);
    background: #ffffff;
    &:hover {
      color: #9800c8;
      border-color: #9800c8;
    }
  }
  :deep(.el-pager .is-active) {
    font-weight: 500;
    &:hover {
      color: #fff;
    }
  }
}
.autoHeight-enter-active,
.autoHeight-leave-active {
  max-height: 200px;
  transition: all 0.3s;
  overflow: hidden;
}
.autoHeight-enter-from,
.autoHeight-leave-to {
  max-height: 0;
}
.el-button + .is-text {
  margin: 0 !important;
}
</style>
